
#include "core/job_manager.h"
#include "core/utils.h"
#include "vetest.h"

#include <string.h>

/***********************************************************************/

struct test_simple_job_data
{
	int value;
};

void test_simple_job( const VEJobData *data, int thread_id )
{
	struct test_simple_job_data * tdata = (struct test_simple_job_data*)data->context;

	tdata->value = 1;
}

void test_simple( int priority )
{
	VEJobState state;
	VEJobData jdata;
	struct test_simple_job_data data;

	data.value = 0;

	memset( &jdata, 0, sizeof(jdata) );
	jdata.context = &data;
	ve_job_start( &state, &jdata, test_simple_job, 0, priority, 0 );
	ve_job_wait( &state, 0 );

	VE_VERIFY( data.value == 1 );
}

/***********************************************************************/

#define TEST_JOB_COUNT 1024

void test_many( int priority )
{
	int i;

	VEJobState state[TEST_JOB_COUNT];
	VEJobData jdata[TEST_JOB_COUNT];
	struct test_simple_job_data data[TEST_JOB_COUNT];

	memset( data, 0, sizeof(data) );
	memset( jdata, 0, sizeof(jdata) );

	for( i = 0; i < TEST_JOB_COUNT; ++i )
	{
		jdata[i].context = &data[i];
		ve_job_start( &state[i], &jdata[i], test_simple_job, 0, priority, 0 );
	}

	for( i = 0; i < TEST_JOB_COUNT; ++i )
	{
		ve_job_wait( &state[i], 0 );
		VE_VERIFY( data[i].value == 1 );
	}
}

/***********************************************************************/

struct test_loop_job_data
{
	int value[TEST_JOB_COUNT];
};

void test_loop_job( const VEJobData *data, int thread_id )
{
	int i;
	struct test_loop_job_data * tdata = (struct test_loop_job_data*)data->context;

	for( i = data->range.num.begin; i < data->range.num.end; ++i )
		tdata->value[i] = 1;
}

int test_loop_job_splitter( VEJobData *old_data, VEJobData *new_data, int mode )
{
	const int min_size = 16;
	if( old_data->range.num.end - old_data->range.num.begin < 2 * min_size )
		return 0;

	if( mode == JOB_SPLIT_MODE_POP )
		new_data->range.num.end = old_data->range.num.begin + min_size;
	else
		new_data->range.num.end = (old_data->range.num.begin + old_data->range.num.end) / 2;

	old_data->range.num.begin = new_data->range.num.end;

	return 1;
}

void test_loop( int priority )
{
	int i;
	VEJobState state;
	VEJobData jdata;
	struct test_loop_job_data data;

	memset( &data, 0, sizeof(data) );
	memset( &jdata, 0, sizeof(jdata) );
	jdata.context = &data;
	jdata.range.num.begin = 0;
	jdata.range.num.end   = TEST_JOB_COUNT;

	ve_job_start( &state, &jdata, test_loop_job, test_loop_job_splitter, priority, 0 );
	ve_job_wait( &state, 0 );

	for( i = 0; i < TEST_JOB_COUNT; ++i )
		VE_VERIFY( data.value[i] == 1 );
}

/***********************************************************************/

int main( int argc, char *argv[] )
{
	ve_job_manager_init();

	test_simple( JOB_PRIORITY_NORMAL );
	test_simple( JOB_PRIORITY_LOW );
	test_simple( JOB_PRIORITY_BACKGROUND );

	test_many( JOB_PRIORITY_NORMAL );
	test_many( JOB_PRIORITY_LOW );
	test_many( JOB_PRIORITY_BACKGROUND );

	test_loop( JOB_PRIORITY_NORMAL );
	test_loop( JOB_PRIORITY_LOW );
	test_loop( JOB_PRIORITY_BACKGROUND );

	ve_job_manager_done();

	return 0;
}

